/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2006，所有权利保留。
 * 
 * 文件名：	BCartFunctionView.java
 * 模块说明：	
 * 修改历史：
 * 2006-10-25 - lxm - 创建。
 */
package com.hd123.rumba.cartridge.biz;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;

import org.w3c.dom.Element;

import com.hd123.rumba.cartridge.FVRumbaSystemCommon;
import com.hd123.rumba.cartridge.entry.Entry;
import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.domain.biz.IBDomainMgr;
import com.hd123.rumba.domain.biz.SDomain;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.exception.ParameterException;
import com.hd123.rumba.gwt.base.client.exception.ClientBizException;
import com.hd123.rumba.navigation.menu.BMenu;
import com.hd123.rumba.navigation.menu.IBMenuMgr;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.IPersistent;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.biz.BVersionedPersistent;
import com.hd123.rumba.user.IUser;

/**
 * 构件包功能视图 | 业务层.维护 | 实体
 * <p>
 * 
 * 功能视图间存在功能依赖关系BCartFuncViewReference。
 * <p>
 * 
 * 构件包设计者需要决定定义多少个功能视图，以便系统实施人员可以将其加载给指定的域。
 * 
 * @author lxm
 * 
 */
public abstract class BCartFunctionView extends BVersionedPersistent {

  /** 属性：所属域 */
  private SDomain domain;
  /** 属性：所属构件包 */
  private SCartridge cartridge;
  /** 属性：唯一前缀 */
  private String prefix;
  /** 属性：标题 */
  private String caption;
  /**
   * 属性：是抽象的<br>
   * 所谓抽象功能视图，表示系统实施人员不可单独将其加载给指定的域。
   */
  private Boolean isAbstract;
  /** 属性：说明 */
  private String remark;
  /** 属性：依赖关系列表 */
  private List<BCFVReference> references;
  /** 返回创建的EntryLink对象。 */
  private HashMap<String, Entry> entries;
  /** 属性：主菜单 */
  private BMenu mainMenu;

  public BCartFunctionView() {
    super();
    uuid = this.getClass().getName();
    try {
      IBDomainMgr dmMgr = (IBDomainMgr) NamingMgr.getInstance().lookupMgr(IBDomainMgr.class);
      domain = dmMgr.getRootDomain();
    } catch (Exception e) {
      domain = null;
    }
    caption = uuid;
    prefix = "";
    isAbstract = Boolean.FALSE;
    references = new ArrayList();
    entries = null;
    mainMenu = null;
    fetchPropValues();
  }

  public SCartFunctionView cloneSimple() throws BusinessException {
    SCartFunctionView scfv = new SCartFunctionView();
    try {
      scfv.setUuid(this.uuid);
    } catch (ClientBizException e) {
      throw new BusinessException(e);
    }
    scfv.setPrefix(this.prefix);
    scfv.setCaption(this.caption);
    return scfv;
  }

  public void readFrom(IPersistent source) throws BusinessException {
    throw new BusinessException("Never call me!");
  }

  /**
   * 数据初始化。<br>
   * 设计者要求当对象被创建后，应该尽快调用此方法。
   * 
   * @throws BusinessException
   */
  public void init(Element e) throws BusinessException {
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);
    cartMgr.initCFVByConfig(this, e);
  }

  /**
   * 取得全局标题
   * 
   * @return
   */
  public String getGlobalCaption() {
    try {
      return this.cartridge.getCaption() + "." + this.caption;
    } catch (Exception e) {
      return this.caption;
    }
  }

  /**
   * 返回是否依赖指定的构件包功能视图。
   * 
   * @param referredCFVUuid
   *          返回是否依赖指定的构件包功能视图。
   * @return true|false
   * @deprecated instead of
   * @link{#isReferring2(String)};
   */
  public boolean isReferring(String referredCFVUuid) {
    boolean ret = false;
    try {
      IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
          IBCartridgeMgr.class);
      String refPrefix = cartMgr.getFunctionView(referredCFVUuid).getPrefix();
      for (int i = 0; i < references.size(); i++)
        if (references.get(i).getRefCFVPrefix().equals(refPrefix)) {
          ret = true;
          break;
        }
      return ret;
    } catch (BusinessException e) {
      return false;
    }
  }

  /**
   * 返回是否依赖指定的构件包功能视图。
   * 
   * @param referredCFVPrefix
   *          返回是否依赖指定的构件包功能视图的前缀。
   * @return
   */
  public boolean isReferring2(String referredCFVPrefix) {
    boolean ret = false;
    for (int i = 0; i < references.size(); i++)
      if (references.get(i).getRefCFVPrefix().equals(referredCFVPrefix)) {
        ret = true;
        break;
      }
    return ret;
  }

  /**
   * 返回是否可以被装载到指定域。
   * 
   * @param domain
   *          指定的域
   * @return 返回true或false。
   * @throws BusinessException
   * @throws HibernateException
   */
  public abstract boolean canLoadToDomain(IDomain domain) throws BusinessException,
      HibernateException;

  /**
   * 当被装载到指定域的时候被调用的处理。
   * 
   * @param domain
   *          指定域。
   * @param operator
   *          当前操作人。
   * @throws BusinessException
   * @throws HibernateException
   * @throws InterruptedException
   */
  public abstract void onLoadToDomain(IDomain domain, IUser operator) throws BusinessException,
      HibernateException, InterruptedException;

  /**
   * 当被从指定域卸载的时候被调用的处理。
   * 
   * @param domain
   *          指定域。
   * @param operator
   *          当前操作人。
   * @throws BusinessException
   * @throws HibernateException
   * @throws InterruptedException
   */
  public abstract void onUnloadFromDomain(IDomain domain, IUser operator) throws BusinessException,
      HibernateException, InterruptedException;

  /**
   * 将指定的Entry对象放入entries中，key为id。
   * 
   * @param entry
   *          指定被放入的Entry对象。
   * @throws BusinessException
   */
  protected void putEntry(Entry entry) throws BusinessException {
    this.checkParameterNotNull(entry, "entry");
    this.entries.put(entry.getId(), entry);
  }

  /**
   * 添加一个模块功能入口。
   * 
   * @param id
   *          指定模块功能入口对象的标识。
   * @param caption
   *          指定模块功能入口的标题。
   * @return 返回创建并已经被添加到entries的模块功能入口对象。
   * @throws BusinessException
   */
  protected Entry appendEntry(String id, String caption) throws BusinessException {
    this.checkParameterNotNull(id, "id");
    Entry entry = new Entry(this);
    entry.setId(id);
    entry.setCaption(caption);
    this.entries.put(id, entry);
    return this.entries.get(id);
  }

  /**
   * 在当前构件包功能视图范围内搜索，查找指定id的模块功能入口对象。
   * 
   * @param id
   *          指定的模块功能入口id。
   * @return 返回符合条件的模块功能入口对象，若找不到则返回null。
   * @throws BusinessException
   */
  public Entry getEntryById(String id) throws BusinessException {
    return this.getEntries().get(id);
  }

  /**
   * 查找指定id的模块功能入口对象。
   * 
   * @param cfvClass
   *          指定的构件包功能视图。
   * @param id
   *          指定的模块功能入口id。
   * @return 返回符合条件的模块功能入口对象，若找不到则返回null。
   * @throws BusinessException
   */
  public Entry getEntryById(Class cfvClass, String id) throws BusinessException {
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);
    return cartMgr.getEntryById(cfvClass, id);
  }

  /**
   * 取得显示欢迎页面的模块功能入口对象。
   * 
   * @return 返回模块功能入口对象。
   * @throws BusinessException
   */
  protected Entry getWelcomeEntry() throws BusinessException {
    return this.getEntryById(FVRumbaSystemCommon.class, FVRumbaSystemCommon.ID_ENTRY_WELCOME);
  }

  /**
   * 构造所包含的模块功能入口映射表。
   * 
   * @throws BusinessException
   */
  protected abstract void buildEntries() throws BusinessException;

  /**
   * 构造功能视图所对应的主菜单。
   * 
   * @param mainMenu
   *          指定主菜单，传入传出参数。传入已经创建好的空的菜单对象。
   * @throws BusinessException
   */
  protected abstract void buildMainMenu(BMenu mainMenu) throws BusinessException;

  protected Session getSession() throws HibernateException {
    return HibernateSession.getSession();
  }

  protected void checkParameterNotNull(Object param, String paramName) throws ParameterException {
    if (param == null)
      throw new ParameterException("必须的参数" + paramName + "不能为null");
  }

  public String getCaption() {
    return caption;
  }

  void setCaption(String caption) {
    this.caption = caption;
  }

  public SCartridge getCartridge() {
    return cartridge;
  }

  void setCartridge(SCartridge cartridge) {
    this.cartridge = cartridge;
  }

  public SDomain getDomain() {
    return domain;
  }

  void setDomain(SDomain domain) {
    this.domain = domain;
  }

  public Boolean getIsAbstract() {
    return isAbstract;
  }

  void setIsAbstract(Boolean isAbstract) {
    this.isAbstract = isAbstract;
  }

  public String getPrefix() {
    return prefix;
  }

  public List<BCFVReference> getReferences() {
    return references;
  }

  public String getRemark() {
    return remark;
  }

  void setRemark(String remark) {
    this.remark = remark;
  }

  public BMenu getMainMenu() throws BusinessException {
    if (this.mainMenu == null) {
      IBMenuMgr menuMgr = (IBMenuMgr) NamingMgr.getInstance().lookupMgr(IBMenuMgr.class);
      try {
        this.mainMenu = menuMgr.createMenu();
      } catch (HibernateException e) {
        throw new BusinessException(e);
      }
      this.buildMainMenu(this.mainMenu);
    }
    return mainMenu;
  }

  private void fetchPropValues() {
    Field[] fields = this.getClass().getDeclaredFields();
    for (int i = 0; i < fields.length; i++)
      try {
        if ("FUNCV_PREFIX".equals(fields[i].getName()))
          prefix = (String) fields[i].get(null);
      } catch (IllegalArgumentException e) {
      } catch (IllegalAccessException e) {
      }
  }

  public HashMap<String, Entry> getEntries() throws BusinessException {
    if (this.entries == null) {
      this.entries = new HashMap();
      this.buildEntries();
    }
    return entries;
  }
}
